package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import lombok.SneakyThrows;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @SneakyThrows
    @Override
    public void testLock() {
         /*
        1.  在缓存中初始化一个num 值 0    set num 0; String
        2.  将缓存中的num 读取到程序中，
                num == null，则直接返回！
                num != null, num+1;
         */
        // 上锁：
        RLock myLock = redissonClient.getLock("myLock");

        //  尝试获取锁！
        boolean result = myLock.tryLock(5, 3, TimeUnit.SECONDS);
        if (result){
            try {
                //  获取资源
                String num = redisTemplate.opsForValue().get("num");
                //  判断
                if (StringUtils.isEmpty(num)) {
                    return;
                }
                //  将num + 1 放入缓存！ 数据类型转换
                int numValue = Integer.parseInt(num);
                this.redisTemplate.opsForValue().set("num", String.valueOf(++numValue));

            }finally {
                myLock.unlock();
            }
        }else {
            Thread.sleep(new Random().nextInt(5)*1000);
            testLock();
        }
        // myLock.lock();
        //        try {
        //            //  获取资源
        //            String num = redisTemplate.opsForValue().get("num");
        //            //  判断
        //            if (StringUtils.isEmpty(num)) {
        //                return;
        //            }
        //            //  将num + 1 放入缓存！ 数据类型转换
        //            int numValue = Integer.parseInt(num);
        //            this.redisTemplate.opsForValue().set("num", String.valueOf(++numValue));
        //        } catch (NumberFormatException e) {
        //            e.printStackTrace();
        //        } finally {
        //            myLock.unlock();
        //        }

    }

    @Override
    public String readLock() {
        //  读取数据：   读取redis 中 key = msg 的数据
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  创建读锁：
        rwlock.readLock().lock(10,TimeUnit.SECONDS);
        //  获取数据
        String msg = this.redisTemplate.opsForValue().get("msg");

        return msg;
    }

    @Override
    public String writeLock() {
        //  创建对写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  创建写锁！
        rwlock.writeLock().lock(10,TimeUnit.SECONDS);
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());

        return "写入完成....";
    }


    //  测试方法！
//    @Override
//    public synchronized void testLock() {
//        /*
//        1.  在缓存中初始化一个num 值 0    set num 0; String
//        2.  将缓存中的num 读取到程序中，
//                num == null，则直接返回！
//                num != null, num+1;
//         */
//
//        //  做分布式锁： setnx
//        //  Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", "atguigu");
//        //  set key value ex/px timeout nx/xx;
//        String uuid = UUID.randomUUID().toString();
//        Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
//        //  result = true
//
//        if (result){
//            //  获取资源
//            String num = redisTemplate.opsForValue().get("num");
//            //  判断
//            if(StringUtils.isEmpty(num)){
//                return;
//            }
//
//            //  int i = 1/0;
//            //  将num + 1 放入缓存！ 数据类型转换
//            int numValue= Integer.parseInt(num);
//            this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
//
//            //  释放锁！
//            //  判断uuid 是否相等！
//            //  定义lua 脚本
//            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
//
//            //  执行lua 脚本：
//            //  第一个： 表示 RedisScript 需要执行的lua 脚本 第二个： key 第三个： value
//            DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
//            defaultRedisScript.setScriptText(script);
//            defaultRedisScript.setResultType(Long.class);
//            this.redisTemplate.execute(defaultRedisScript, Arrays.asList("lock"),uuid);
//
//            //            if (uuid.equals(redisTemplate.opsForValue().get("lock"))){
//            //                //  index1 进入了if 说明你的本地uuid 与缓存一致！ 但是，在没有执行删除代码时，
//            //                //  index2 获取到资源， 缓存的lock key 对应的uuid 发生了变化！
//            //                this.redisTemplate.delete("lock");
//            //            }
//
//        }else {
//            //  没有获取到锁！
//            try {
//                Thread.sleep(200);
//                //  重试
//                testLock();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//
//
//    }
}
